#include "Expresie.h"
#include <string.h>
#include <sstream>
Functie::Functie(std::string ss)
{
    this->expresie=ss;
}
int Functie::isOperator(char c)
{
    switch (c) {
        case '+':case '-':return 1+paranteza;
        case '*':case '/':return 2+paranteza;
        case '^':return 3;
    }
    return 0;
}

void Functie::formaPoloneza()
{
    int i=0;
    paranteza=0;
    while (i<this->expresie.size())
    {
        if (isdigit(this->expresie[i]))
            {
                std::string numar;
                while(isdigit(this->expresie[i])||expresie[i]=='.')
                      { 
                          numar=numar+expresie[i];
                          i++;
                      }
                i--;
                this->polonez.push_back(numar);
            }
        if(isOperator(this->expresie[i]))
        {
            if (operatori.size()>0)
            {
                if (isOperator(expresie[i])<=operatori.back().val)
                    {
                        while ((isOperator(expresie[i])<=operatori.back().val)&&(operatori.size()>0))
                        {
                            polonez.push_back(operatori.back().getType());
                            operatori.pop_back();
                        }
                    }
            }
            op newestOP(isOperator(expresie[i]),expresie[i]);
            operatori.push_back(newestOP);
            }
        if (expresie[i]=='(')
        {
            op temp_op(0,'(');
            paranteza+=10;
            operatori.push_back(temp_op);
        }
        if (expresie[i]=='x')
        {
            polonez.push_back("x");
        }
        if (expresie[i]==')')
        {
            paranteza-=10;
            while (operatori[operatori.size()-1].getType()!="(")
            {
                polonez.push_back(operatori[operatori.size()-1].getType());
                operatori.pop_back();
            }
            operatori.pop_back();
        }
        std::string str=expresie.substr(i,3);
        if (str=="sin")
        {
            op SIN(5,"SIN");
            operatori.push_back(SIN);
            //polonez.push_back("sin");
            i+=2;
        }
        else if(str=="cos")
        {
            op COS(5,"COS");
            operatori.push_back(COS);
            i+=2;
        }
        else if (str=="tan")
        {
            op TAN(5,"TAN");
            operatori.push_back(TAN);
            i+=2;
        }
        else if (str=="ctg")
        {
            op CTG(5,"CTG");
            operatori.push_back(CTG);
            i+=3;
        }
        i++;
    }
    while (operatori.size()>0)
    {
        polonez.push_back((operatori.back()).getType());
        operatori.pop_back();
        
    }
}
void Functie::print()
{
    std::cout<<"SIR POLONEZ:";
    for (int i=0; i<polonez.size();i++)
    {
        std::cout<<polonez[i]<<' ';
    }
    std::cout<<std::endl;
}
void Functie::creareArbore()
{
    formaPoloneza();
    int level=0;
    
    while (level!=polonez.size())
    {
        if (polonez[level]=="SIN")
        {
            Sin *nodSin=new Sin;
            nodSin->fStang=stNod.top();
            stNod.pop();
            stNod.push(nodSin);
            //level++;
        }
        if (polonez[level]=="COS")
        {
            Cos *nodCos=new Cos;
            nodCos->fStang=stNod.top();
            stNod.pop();
            stNod.push(nodCos);
            // level++;
        }
        if (polonez[level]=="TAN")
        {
            Tan* nodTan=new Tan;
            nodTan->fStang=stNod.top();
            stNod.pop();
            stNod.push(nodTan);
        }
        if (polonez[level]=="CTG")
        {
            Ctan* nodCtan=new Ctan;
            nodCtan->fStang=stNod.top();
            stNod.pop();
            stNod.push(nodCtan);
        }
        if(!isOperator(polonez[level][0]))
        {
            if (polonez[level]=="x")
            {
                Necunoscuta *n=new Necunoscuta();
                stNod.push(n);
                // level++;
            }
            else if (polonez[level]!="SIN" && polonez[level]!="COS"&& polonez[level]!="TAN" && polonez[level]!="CTG")
            {
                long double valoare=atof(polonez[level].c_str());
                Constanta *t=new Constanta(valoare);
                stNod.push(t);
                //level++;
            }
        }
        if (isOperator(polonez[level][0])){
                switch (polonez[level][0]) {
                    case '-':{
                        Minus *nodMinus=new Minus;
                        nodMinus->fDrept=stNod.top();
                        stNod.pop();
                        nodMinus->fStang=stNod.top();
                        stNod.pop();
                        stNod.push(nodMinus); 
                        break;}                  
                    case '+':{
                        Plus *nodPlus=new Plus;
                        nodPlus->fDrept=stNod.top();
                        stNod.pop();
                        nodPlus->fStang=stNod.top();
                        stNod.pop();
                        stNod.push(nodPlus);
                        // std::cout<<"Making calculus:";
                        //std::cout<<std::endl<<nodPlus->fStang->calcul()<<' '<<nodPlus->fDrept->calcul()<<" works"<<std::endl;
                        break;
                    }
                    case '*':
                    {
                        Produs* nodProdus=new Produs;
                        nodProdus->fStang=stNod.top();
                        stNod.pop();
                        nodProdus->fDrept=stNod.top();
                        stNod.pop();
                        stNod.push(nodProdus);
                        break;
                    }
                    case '/':
                    {
                        Impartire* nodImpartire=new Impartire;
                        nodImpartire->fDrept=stNod.top();
                        stNod.pop();
                        nodImpartire->fStang=stNod.top();
                        stNod.pop();
                        stNod.push(nodImpartire);
                        break;
                    }
                    case '^':
                    {
                        Putere* nodPutere=new Putere;
                        nodPutere->fStang=stNod.top();
                        stNod.pop();
                        nodPutere->fDrept=stNod.top();
                        stNod.pop();
                        stNod.push(nodPutere);
                    }
            }
            //level++;                                                                                                                                                                             
        }
        level++;
    }
}
long double Functie::calcul()
{
    creareArbore();
    print();
    return (*stNod.top()).calcul();
}
std::string Functie::derivare()
{
    creareArbore();
    return (*stNod.top()).derivare();
}